/**
 * 
 */
package de.fsujena.chat_pi.client;

import java.io.BufferedReader;
import java.io.Console;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;

import de.fsujena.chat_pi.message.SysMessage;
import de.fsujena.chat_pi.message.SysMessage.CATEGORY;
import de.fsujena.chat_pi.message.SysMessage.MESSAGE;
import de.fsujena.chat_pi.message.TextMessage;

/**
 * @author erik
 * 
 */
public class Client {

	public ConnectionThread connectionThread = null; 	//Thread that handels the connection to the server
	public Boolean isconnected = false; 				//connectionstate of the client
	public String ipadress = null;						//the ipadress of the server
	public int port = 0;								//the port on which the server runs
	String username;									//the username with wich the user is logged in
	String password;									//the password of the user //TODO encrypt this
	// Console console = System.console();
	Console console = null;								//reference to the system console(not realy needed)
	BufferedReader input = new BufferedReader(new InputStreamReader(System.in));	

	/**
	 * @param args
	 */
	/**starts the client
	 * @param args unused
	 */
	public static void main(String[] args) {
		new Client().startClient();
	}

	// TODO Auto-generated method stub
	/**
	 * reads the input and processes it
	 */
	void startClient() {

		while (true) {
			String cmd = null;
			try {
				cmd = input.readLine();		//read from console

			} catch (Exception e) {
				e.printStackTrace();

			}

			if (cmd.startsWith("$")) {		//checks if input is a command
				// check the command
				commander(cmd);				//yes? call commander
			} else if (isconnected)
				sendTextMessage(cmd);		//no? must be a message so send it to the server (if already connected)
			else
				showStatus();				//not connected? show it to the user

		}
	}

	/**
	 * send a TextMessage to the server
	 * @param msg string containing the message
	 */
	public void sendTextMessage(String msg) {

		// TODO implement message sending
		TextMessage textMsg = new TextMessage(msg);			//creates new TextMessage object
		textMsg.setSent(new Date());							//writes the actual date to the message
		textMsg.setSenderUsername(username);					//writes the username to the message
		connectionThread.sendMessage(textMsg);				//send it via the connectionthread
		return;
	}

	/**
	 * sends a systemmessage
	 * @param cat category of the message (see SysMessage class for details)
	 * @param msg message code (see SysMessage class for details)
	 */
	public void sendSysMessage(SysMessage.CATEGORY cat, SysMessage.MESSAGE msg) {
		SysMessage sysMsg = new SysMessage(cat, msg);		//create new systemmessage object
		sysMsg.setSent(new Date());							//write the date
		sysMsg.setSenderUsername(username);					//write the username of the sender
		connectionThread.connector.sendObject(sysMsg);		//send via connectionthread
	}
	/**
	 * sends a systemmessage
	 * @param cat category of the message (see SysMessage class for details)
	 * @param msg message code (see SysMessage class for details)
	 */
	public void sendSysMessage(SysMessage.CATEGORY cat, SysMessage.MESSAGE msg,
			String msgStr) {
		SysMessage sysMsg = new SysMessage(cat, msg, msgStr);
		sysMsg.setSent(new Date());
		sysMsg.setSenderUsername(username);
		connectionThread.connector.sendObject(sysMsg);
	}

	/**
	 * evaluates the userinput
	 * @param command string containing userinput
	 */
	public void commander(String command) {
		
		String[] arg = command.split(" "); 					//splits input on every " " (arg[0] should contain"$")

		if ((arg[1].equals("connect"))) {					//if command is connect start connecting to server
			if (arg.length == 3) {							//length have to be 3 because it consists of $+connect+"ip:port"
				String[] arg2 = arg[2].split(":");			//Separate ip and port
				if (arg2.length == 2) {						//length should be 2
					ipadress = arg2[0];
					try {
						port = Integer.parseInt(arg2[1]);	//converts port-string into integer
					} catch (NumberFormatException e) {			
						// TODO Auto-generated catch block
						// e.printStackTrace();
						System.out.println("invalid port");	//on exception show error
						showStatus();
						return;

					}

					connect(ipadress, port);				//connect to server
				} else
					System.out.println("invalid number of parameters");	//show error if number of parameter didn't match
			} else
				System.out.println("invalid number of parameters");		//show error if number of parameter didn't match
		} else if (arg[1].equals("disconnect"))		
			disconnect();												//disconnect from the server
		else if (arg[1].equals("status"))
			showStatus();												//give the state of the connection
		else if (arg[1].equals("help"))
			showHelp();													//open help
		else if (arg[1].equals("exit"))
			killClient();												//stop client
		else if (arg[1].equals("login"))								//log in server
			if (arg.length == 4)										//check number of arguments
				login(arg[2], arg[3]);
			else
				System.out.println("invalid number of parameters");		//invalid number of arguments
		else if (arg[1].equals("register"))
			if (arg.length == 4)										//check number of arguments
				register(arg[2], arg[3]);								//register on the server
			else
				System.out.println("invalid number of parameters");		//ect.
		else if (arg[1].equals("userlist"))
			sendSysMessage(CATEGORY.STATUS, MESSAGE.REQUEST_USER_LIST);	//request userlist
		else if (arg[1].equals("logout"))								//log out
			logout();
		else
			System.out.println("invalid command type $ help to see a list off commands");	//no valid command
		return;
	}

	/**
	 * tells the server that you want to logout
	 */
	private void logout() {
		// TODO implement logout routine
		sendSysMessage(CATEGORY.LOGIN, MESSAGE.LOGGED_OUT, username);	//tells the server that user "username" wants to logout
		// connectionThread.disconnect();
		
		// TODO somewhere there is an infinite loop causing to send logout message endlessly
		
		return;
	}

	/**
	 * start connectionthread which connects to the server
	 * @param ip the ipadress of the server
	 * @param port	the port on which the server is running
	 */
	public void connect(String ip, int port) {

		try {
			connectionThread = new ConnectionThread(ip, port);		//create new thread
		} catch (IOException e1) {									//error on connecting?
			// TODO Auto-generated catch block
			// e1.printStackTrace();
			isconnected = false;									//flag as not connected
			showStatus();											//show that to the user
			System.out.println("couldn't connect to server");		//show it again
			e1.printStackTrace();					
			return;
		}
		isconnected = connectionThread.server.isConnected();		//flag as connected 

		if (!isconnected) {											//show the status of the connection
			showStatus();
			return;
		}
		connectionThread.start();									//starts the thread
		connectionThread.mainThread = this;							//give him the reference to the main thread

		return;
	}

	/**
	 * disconnect from the server
	 */
	public void disconnect() {
		// TODO implement server disconnect
		sendSysMessage(CATEGORY.CONNECTION, MESSAGE.DISCONNECTED, username);		//tell the server that your are going to disconnect
		if (connectionThread != null){												
			connectionThread.disconnect();											//disconnect
			connectionThread=null;													//free resources
		}
		isconnected = false;														//flag as disconnected
		return;
	}

	/**
	 * show help text
	 */
	public void showHelp() {
		// TODO create help text
		return;
	}

	/**
	 * stops the programm
	 */
	public void killClient() {
		disconnect();			//disconnect from the server
		System.exit(0);			//stop the main thread
		return;
	}

	/**
	 *show the status of the connection 
	 */
	public void showStatus() {

		if ((connectionThread != null) && (connectionThread.server != null)) {		//control if connectionthread and server socket exists(could throw null pointer exception otherwise)
			isconnected = connectionThread.server.isConnected();					//get state of connection
		} else
			isconnected = false;													//if thread doesn't exists flag as not connected
		if (isconnected == true) {													//if connected
			System.out.print("connected to server " + ipadress + " on port:"		//tell that the user
					+ port + "\n");
		} else {
			System.out.println("not connected to server");							//if not 
			System.out.println("type 'cmd help' to see commands \n");				//tell them
		}
		return;
	}

	/**
	 * ask the user to type in his username
	 * @return string containing the username
	 */
	public String getUsername() {
		System.out.println("Enter Username:");			//ask him about his name
		try {
			String name = input.readLine();				//get the input
			return name;								//return it
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * aks the user about the password
	 * @param newuser flag if a new user
	 * @return	string containing the password
	 */
	public String getPassword(Boolean newuser) {
		System.out.println("Enter Password:");		//ask for the password
		String passwd;
		String passwd2;
		try {

			if (console != null) {								//only if there actually is a console (there is no console in eclipse)
				passwd = new String(console.readPassword());	//read password from console with masked characters
			} else {
				passwd = input.readLine();						//without console read as standard input
			}
			if (newuser) {											//if its a new user
				System.out.println("New user reenter Password:");	//he has to confirm password
				if (console != null) {								//same as above
					passwd2 = new String(console.readPassword());
				} else {
					passwd2 = input.readLine();
				}
				if (passwd2.equals(passwd)) {						//check if passwordsd match
					return passwd;									//if it matches return the password
				} else
					return null;
			} else
				return passwd;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * Initialize the login process
	 * @param name username to login
	 * @param pass password of the user		
	 */
	public void login(String name, String pass) {
		sendSysMessage(CATEGORY.LOGIN, MESSAGE.WANT_TO_LOGIN);	//tell the server that you want to login

		this.username = name;									//save username for later use
		this.password = pass;									//save password for later use

		connectionThread.username = name;						//save username for later use
		connectionThread.password = pass;						//save password for later use

		return;
	}

	/**
	 * Initialize the registration process
	 * @param name username to register
	 * @param pass the password of the user
	 */
	public void register(String name, String pass) {
		sendSysMessage(CATEGORY.REGISTRATION, MESSAGE.WANT_TO_REGISTER);	//tell the server that you want to register a new user

		this.username = name;												//save username for later use
		this.password = pass;												//save password for later use

		connectionThread.username = name;									//save username for later use
		connectionThread.password = pass;									//save password for later use

		return;
	}
}
